using EasyElasticLogger.NETFramework.ES.Clients;
using EasyElasticLogger.NETFramework.ES.Configuration;
using EasyElasticLogger.NETFramework.ES.Indexing;
using EasyElasticLogger.NETFramework.ES.Models;
using Nest;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using LogLevel = EasyElasticLogger.NETFramework.ES.Models.LogLevel;

namespace EasyElasticLogger.NETFramework.ES.Logging
{
    /// <summary>
    /// Elasticsearch 日志记录器
    /// </summary>
    public static class ElasticLogger
    {
        private static LoggerConfiguration _config;
        private static LogBuffer _logBuffer;
        
        /// <summary>
        /// 静态构造函数
        /// </summary>
        static ElasticLogger()
        {
            // 使用默认配置初始化
            Initialize(ConfigurationProvider.Default());
        }

        /// <summary>
        /// 初始化日志记录器（使用指定配置）
        /// </summary>
        /// <param name="config">日志记录器配置</param>
        public static void Initialize(LoggerConfiguration config)
        {
            _config = config ?? throw new ArgumentNullException(nameof(config));
            _logBuffer = new LogBuffer(1000);

            // 初始化Elasticsearch客户端
            ElasticClientFactory.Initialize(config);
        }

        /// <summary>
        /// 初始化日志记录器（使用指定环境的配置）
        /// </summary>
        /// <param name="environment">环境名称（如：Development、Test、Production）</param>
        public static void Initialize(string environment)
        {
            Initialize(ConfigurationProvider.FromAppConfig(environment));
        }

        /// <summary>
        /// 初始化日志记录器（使用指定配置文件和环境）
        /// </summary>
        /// <param name="configFilePath">配置文件路径（兼容AutoCAD二次开发）</param>
        /// <param name="environment">环境名称（如：Development、Test、Production）</param>
        public static void Initialize(string configFilePath, string environment)
        {
            Initialize(ConfigurationProvider.FromMappedConfig(configFilePath, environment));
        }

        /// <summary>
        /// 初始化日志记录器（使用JSON配置文件）
        /// </summary>
        /// <param name="jsonFilePath">JSON文件路径</param>
        public static void InitializeFromJson(string jsonFilePath)
        {
            Initialize(ConfigurationProvider.FromJsonFile(jsonFilePath));
        }

        /// <summary>
        /// 初始化日志记录器（使用JSON配置文件和环境）
        /// </summary>
        /// <param name="jsonFilePath">JSON文件路径</param>
        /// <param name="environment">环境名称</param>
        public static void InitializeFromJson(string jsonFilePath, string environment)
        {
            Initialize(ConfigurationProvider.FromJsonFile(jsonFilePath, environment));
        }

        /// <summary>
        /// 同步写入日志
        /// </summary>
        /// <param name="level">日志级别</param>
        /// <param name="message">日志消息</param>
        /// <param name="exception">异常信息</param>
        /// <param name="source">日志来源</param>
        /// <param name="data">附加数据</param>
        /// <returns>是否写入成功</returns>
        public static bool WriteLog(LogLevel level, string message, Exception exception = null, string source = null, object data = null)
        {
            if (_config == null || !_config.Enabled)
                return false;

            try
            {
                var logEntry = CreateLogEntry(level, message, exception, source, data);
                return WriteLogEntry(logEntry);
            }
            catch (Exception ex)
            {
                Trace.WriteLine($"[ElasticLogger Error] 写入日志时发生异常: {ex}");
                return false;
            }
        }

        /// <summary>
        /// 异步写入日志
        /// </summary>
        /// <param name="level">日志级别</param>
        /// <param name="message">日志消息</param>
        /// <param name="exception">异常信息</param>
        /// <param name="source">日志来源</param>
        /// <param name="data">附加数据</param>
        /// <returns>是否写入成功</returns>
        public static async Task<bool> WriteLogAsync(LogLevel level, string message, Exception exception = null, string source = null, object data = null)
        {
            if (_config == null || !_config.Enabled)
                return false;

            try
            {
                var logEntry = CreateLogEntry(level, message, exception, source, data);
                return await WriteLogEntryAsync(logEntry);
            }
            catch (Exception ex)
            {
                Trace.WriteLine($"[ElasticLogger Error] 异步写入日志时发生异常: {ex}");
                return false;
            }
        }

        /// <summary>
        /// 写入Debug级别日志
        /// </summary>
        public static bool Debug(string message, string source = null, object data = null) =>
            WriteLog(LogLevel.Debug, message, null, source, data);

        /// <summary>
        /// 写入Info级别日志
        /// </summary>
        public static bool Info(string message, string source = null, object data = null) =>
            WriteLog(LogLevel.Info, message, null, source, data);

        /// <summary>
        /// 写入Warn级别日志
        /// </summary>
        public static bool Warn(string message, string source = null, object data = null) =>
            WriteLog(LogLevel.Warn, message, null, source, data);

        /// <summary>
        /// 写入Error级别日志
        /// </summary>
        public static bool Error(string message, Exception exception = null, string source = null, object data = null) =>
            WriteLog(LogLevel.Error, message, exception, source, data);

        /// <summary>
        /// 写入Fatal级别日志
        /// </summary>
        public static bool Fatal(string message, Exception exception = null, string source = null, object data = null) =>
            WriteLog(LogLevel.Fatal, message, exception, source, data);

        /// <summary>
        /// 异步写入Debug级别日志
        /// </summary>
        public static Task<bool> DebugAsync(string message, string source = null, object data = null) =>
            WriteLogAsync(LogLevel.Debug, message, null, source, data);

        /// <summary>
        /// 异步写入Info级别日志
        /// </summary>
        public static Task<bool> InfoAsync(string message, string source = null, object data = null) =>
            WriteLogAsync(LogLevel.Info, message, null, source, data);

        /// <summary>
        /// 异步写入Warn级别日志
        /// </summary>
        public static Task<bool> WarnAsync(string message, string source = null, object data = null) =>
            WriteLogAsync(LogLevel.Warn, message, null, source, data);

        /// <summary>
        /// 异步写入Error级别日志
        /// </summary>
        public static Task<bool> ErrorAsync(string message, Exception exception = null, string source = null, object data = null) =>
            WriteLogAsync(LogLevel.Error, message, exception, source, data);

        /// <summary>
        /// 异步写入Fatal级别日志
        /// </summary>
        public static Task<bool> FatalAsync(string message, Exception exception = null, string source = null, object data = null) =>
            WriteLogAsync(LogLevel.Fatal, message, exception, source, data);

        /// <summary>
        /// 创建日志条目
        /// </summary>
        private static ElasticLogEntry CreateLogEntry(LogLevel level, string message, Exception exception, string source, object data)
        {
            return new ElasticLogEntry
            {
                Timestamp = DateTime.UtcNow,
                Level = level.ToStringValue(),
                Message = message ?? string.Empty,
                Exception = exception?.ToString(),
                Source = source ?? GetDefaultSource(),
                Data = data,
                MachineName = Environment.MachineName,
                ApplicationName = _config?.ApplicationName ?? "DefaultApp",
                ThreadId = Thread.CurrentThread.ManagedThreadId.ToString()
            };
        }

        /// <summary>
        /// 获取默认日志来源
        /// </summary>
        private static string GetDefaultSource()
        {
            var stackTrace = new StackTrace();
            var frames = stackTrace.GetFrames();

            // 跳过当前类的方法
            for (int i = 0; i < frames.Length; i++)
            {
                var method = frames[i].GetMethod();
                var type = method.DeclaringType;

                if (type != typeof(ElasticLogger) && !type.FullName.StartsWith("System."))
                {
                    return $"{type.FullName}.{method.Name}";
                }
            }

            return "Unknown";
        }

        /// <summary>
        /// 写入日志条目
        /// </summary>
        private static bool WriteLogEntry(ElasticLogEntry logEntry)
        {
            try
            {
                var client = ElasticClientFactory.Instance;
                if (client == null)
                {
                    // 客户端未初始化，将日志添加到缓冲区
                    _logBuffer?.Enqueue(logEntry);
                    return false;
                }

                var indexName = IndexManager.GenerateIndexName(_config, logEntry.Timestamp);
                var response = client.Index(logEntry, idx => idx.Index(indexName));

                if (!response.IsValid)
                {
                    // 写入失败，将日志添加到缓冲区
                    _logBuffer?.Enqueue(logEntry);
                    Trace.WriteLine($"[ElasticLogger Warning] 写入Elasticsearch失败: {response.ServerError?.Error?.Reason}");
                    return false;
                }

                return true;
            }
            catch (Exception ex)
            {
                // 发生异常，将日志添加到缓冲区
                _logBuffer?.Enqueue(logEntry);
                Trace.WriteLine($"[ElasticLogger Error] 写入日志条目时发生异常: {ex}");
                return false;
            }
        }

        /// <summary>
        /// 异步写入日志条目
        /// </summary>
        private static async Task<bool> WriteLogEntryAsync(ElasticLogEntry logEntry)
        {
            try
            {
                var client = ElasticClientFactory.Instance;
                if (client == null)
                {
                    // 客户端未初始化，将日志添加到缓冲区
                    _logBuffer?.Enqueue(logEntry);
                    return false;
                }

                var indexName = IndexManager.GenerateIndexName(_config, logEntry.Timestamp);
                var response = await client.IndexAsync(logEntry, idx => idx.Index(indexName));

                if (!response.IsValid)
                {
                    // 写入失败，将日志添加到缓冲区
                    _logBuffer?.Enqueue(logEntry);
                    Trace.WriteLine($"[ElasticLogger Warning] 异步写入Elasticsearch失败: {response.ServerError?.Error?.Reason}");
                    return false;
                }

                return true;
            }
            catch (Exception ex)
            {
                // 发生异常，将日志添加到缓冲区
                _logBuffer?.Enqueue(logEntry);
                Trace.WriteLine($"[ElasticLogger Error] 异步写入日志条目时发生异常: {ex}");
                return false;
            }
        }
    }
}